package com.tanhua.dubbo.es.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.api.UserLocationApi;
import com.tanhua.dubbo.server.pojo.UserLocation;
import com.tanhua.dubbo.server.vo.PageInfo;
import com.tanhua.dubbo.server.vo.UserLocationVo;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.*;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

@Service(version = "1.0.0")
@Slf4j
public class UserLocationApiImpl implements UserLocationApi {
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @PostConstruct
    private void initIndex(){
        if (!this.elasticsearchTemplate.indexExists("tanhua")) {
            this.elasticsearchTemplate.createIndex(UserLocation.class);
        }
        if(!this.elasticsearchTemplate.typeExists("tanhua","user_location")){
            this.elasticsearchTemplate.putMapping(UserLocation.class);
        }
    }
    @Override
    public Boolean updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
        try {
            //查询地理位置是否存在
            GetQuery query=new GetQuery();
            query.setId(String.valueOf(userId));
            UserLocation userLocation = this.elasticsearchTemplate.queryForObject(query, UserLocation.class);
            //查不到数据添加新数据
            if(ObjectUtil.isEmpty(userLocation)){
                userLocation=new UserLocation();
                userLocation.setAddress(address);
                userLocation.setUserId(userId);
                userLocation.setLocation(new GeoPoint(latitude,longitude));
                userLocation.setCreated(System.currentTimeMillis());
                userLocation.setUpdated(userLocation.getCreated());
                userLocation.setLastUpdated(userLocation.getCreated());

                IndexQuery indexQuery=new IndexQueryBuilder().withObject(userLocation).build();

                this.elasticsearchTemplate.index(indexQuery);
            }else {
                //否则更新数据
                //更新的字段
                Map<String,Object>  map=new HashMap<>();
                map.put("location",new GeoPoint(latitude,longitude));
                map.put("address",address);
                map.put("updated",System.currentTimeMillis());
                map.put("lastUpdated", userLocation.getUpdated());


                UpdateRequest updateRequest=new UpdateRequest();
                updateRequest.doc(map);


                UpdateQuery updateQuery=new UpdateQueryBuilder()
                        .withId(String.valueOf(userId))
                        .withClass(UserLocation.class)
                        .withUpdateRequest(updateRequest).build();
                //更新数据到es
                this.elasticsearchTemplate.update(updateQuery);
            }
            return true;
        } catch (Exception e) {
            log.error("更新地理位置失败~ userId = " + userId + ", longitude = " + longitude + ", latitude = " + latitude + ", address = " + address, e);
        }
        return false;
    }

    //查询用户地理位置
    @Override
    public UserLocationVo queryByUserId(Long userId) {

        GetQuery query=new GetQuery();
        query.setId(String.valueOf(userId));
        UserLocation userLocation = this.elasticsearchTemplate.queryForObject(query, UserLocation.class);
        if (ObjectUtil.isEmpty(userLocation)) {
            return null;
        }
        return UserLocationVo.format(userLocation);

    }

    //根据位置搜索
    @Override
    public PageInfo<UserLocationVo> queryUserFromLocation(Double longitude, Double latitude, Double distance, Integer page, Integer pageSize) {
        PageInfo<UserLocationVo> pageInfo=new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);

        //分页
        Pageable pageable= PageRequest.of(page-1,pageSize);

        //查询条件
        BoolQueryBuilder queryBuilder=new BoolQueryBuilder();
        GeoDistanceQueryBuilder geoDistanceQueryBuilder=new GeoDistanceQueryBuilder("location");
        geoDistanceQueryBuilder.distance(distance/1000, DistanceUnit.KILOMETERS);
        geoDistanceQueryBuilder.point(new GeoPoint(latitude,longitude));
        queryBuilder.must(geoDistanceQueryBuilder);

        //排序
        GeoDistanceSortBuilder sortBuilder=new GeoDistanceSortBuilder("location",latitude,longitude);
        sortBuilder.order(SortOrder.ASC);
        sortBuilder.unit(DistanceUnit.KILOMETERS);
        SearchQuery query=new NativeSearchQueryBuilder()
                .withPageable(pageable)
                .withQuery(queryBuilder)
                .withSort(sortBuilder)
                .build();

        AggregatedPage<UserLocation> userLocations = this.elasticsearchTemplate.queryForPage(query, UserLocation.class);
        if (CollUtil.isEmpty(userLocations.getContent())) {
            return pageInfo;
        }

        pageInfo.setRecords(UserLocationVo.formatToList(userLocations.getContent()));
        return pageInfo;
    }
}
